/*
 * MiVentanaRobot.h
 *
 *  Created on: 26/03/2013
 *      Author: gonzalo
 */

#ifndef MIVENTANAEDIFICIO_H_
#define MIVENTANAEDIFICIO_H_

#include "glUtils/glutWindow.h"
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>

#include "Camera.h"
#include "figures/Cilinder.h"
#include "figures/Floor.h"
#include "figures/Grid.h"
#include "figures/CuboTorre.h"
#include "figures/Torre.h"
#include "figures/Lona.h"
#include "figures/PisoInferior.h"
#include "figures/DosPisos.h"
#include "figures/Edificio.h"
#include "figures/PisoMundo.h"
#include "deformacion/DeformacionCurvasBernstein.h"
#include "figures/Rectangle2D.h"
#include "figures/revSurf.h"
#include "figures/Vigas.h"
#include "figures/BezierCubSurf.h"
#include "figures/revSurf.h"
#include "figures/Arbol.h"
#include "figures/TramoTuberia.h"

#include "glUtils/Shader.h"

class MiVentanaEdificio: public cwc::glutWindow {
private:

	// Camaras
	void init_cameras();
	Camera * camara_actual;
	Camera camara1;
	Camera camara2;
	Camera camara3;
	Camera camara4;
	GLfloat altura_camara_2;
	GLfloat zoom_camara_4;

	void init_shaders();
	void init_textures();

	Floor * suelo;
	Edificio * edificio;
	unsigned int textura_piso;
	unsigned int textura_columnas;
	unsigned int textura_escalera;
	unsigned int textura_ladrillo;
	unsigned int textura_pasto;
	unsigned int textura_viga;
	unsigned int textura_piedra;
	unsigned int textura_arena;
	unsigned int textura_tronco;
	unsigned int textura_metal;

	Torre * torre;
	GLfloat largo_cubos;
	GLfloat ancho_cubos;

	Rectangle2D * piso_mundo;

	Rectangle2D * vidrio_interior, *vidrio_exterior, *pared_exterior;

	Vigas* vigas;
	BezierCubSurf *piedras, *arena;
	Arbol *arbol1, *arbol2, *arbol3, *arbol4;
	SweepSurf *tuberia;

	Shader * basicShader;
	Shader * lightingShaderDefor;

	// Luces
	Shader * lightingShader;
	glm::vec3 AmbientalLightIntensity;
	glm::vec4 LightPosition;
	glm::vec4 LightIntensity;
	glm::vec2 LightDirection;

	std::vector<GLuint> texturas;

	// Mouse Control
	bool mouse_trap;
	bool just_warped;
	int centerX;
	int centerY;
	GLfloat mouse_motion_speed;
	GLfloat camera_motion_speed;

	// Skybox
	Shader * skyboxShader;
	Cube * skyboxCube;
	void init_skybox();
	void draw_skybox();
	unsigned int cubemap_texture;
	unsigned int load_cube_map_texture(std::string * filenames);

	// Shadowing
	Shader * simpleShader;
	Shader * shadowShader;
	Camera LightCamera;
	void generate_shadow_buffer();
	GLuint shadowFBO;
	GLuint shadowMapTexture;
	glm::mat4 shadowMatrix;
	GLint shadowMapWidth;
	GLint shadowMapHeight;
	GLfloat znear,zfar;

	unsigned int load_mip_map_texture(const char * filename);

	// Refexion
	Shader * reflectionShader;

	Shader * refractionShader;

	// Pruebas
	Cube ** testCubes;
	unsigned int cantTestCubes;
	Cube * lightCube;
	Cilinder * testCilinder;
	Rectangle2D * testRectangle;

	// Matrices
	glm::mat4 ModelMatrix;
	glm::mat3 NormalMatrix;

	// Matrices Precalculadas
	glm::mat4 ModelViewMatrix;				//only to save time for vertexshader
	glm::mat4 ModelViewProjectionMatrix;	//only to save time for vertexshader

	void calculate_normal_matrix();
	void bind_matrixes(GLuint program);

	void establecerMatrizDeProyeccion(GLuint program_handle);
	void establecerEfectosDeIluminacion(GLuint program_handle);
	void changeObjectColor(GLuint program_handle, float r, float g, float b);

	void render_grid(glm::mat4 model_matrix_grid);
	void render_sphere(glm::mat4 model_matrix, GLfloat * vertex_pointer, GLuint & vertex_pointer_size,
			GLuint * index_pointer, GLuint index_pointer_size);
	void render_cube(glm::mat4 model_matrix, GLfloat * vertex_pointer, GLuint vertex_pointer_size,
			GLuint * index_pointer, GLuint index_pointer_size, GLfloat * normal_pointer,
			GLuint normal_pointer_size);

	void key_handle_move_camera(int nKey, char cAscii);
	void key_handle_arrows(int nKey, char cAscii);
	void key_handle_traslate_object(int nKey, char cAscii);

	unsigned int load_texture(const char* filename);

	void bind_camera_projection(unsigned int shader_id);
	void draw_shadow_map();
	void draw_mirror();
	void draw_scene(Shader * shader);
	void draw_test_cubes(Shader * shader);

public:
	MiVentanaEdificio();
	virtual ~MiVentanaEdificio();

	virtual void OnResize(int w, int h);
	virtual void OnInit();
	virtual void OnRender();
	virtual void OnKeyDown(int nKey, char cAscii);
	virtual void OnKeyUp(int nKey, char cAscii);

	//! Called when Mouse button is pressed
	virtual void OnMouseDown(int button, int x, int y);

	//! Called when Mouse button is released
	virtual void OnMouseUp(int button, int x, int y);

	//! Called when Mouse is moved (without pressing any button)
	virtual void OnMouseMove(int x, int y);

	//! Called while Left Mouse button is pressed.
	virtual void OnLeftMouseDrag(int x, int y);

	//! Called when mouse wheel is used
	virtual void OnMouseWheel(int nWheelNumber, int nDirection, int x, int y);

	virtual void OnIdle(void);
};

#endif /* MIVENTANAROBOT_H_ */
